
#include "network.h"
#include "cpu.h"

net_info *net_working_list, *net_record_list;
int itfc_nbr;
unsigned long ps_total_delta_time;
int is_net_recording;
FILE *net_logger;
char net_filename[BUFFERSIZE];
int *received_speed, *transimitted_speed;
long long total_net_received;
long long total_net_transmitted;
float total_rx_speed;
float total_tx_speed;

void net_dump();
void net_refresh();

void init_network()
{
    if (!cpu_initialized)
            init_cpu();
    int i, rx, tx;
    char name[MAX_NAME_LEN], line[BUFFERSIZE];
    FILE *fp = fopen(NETWORK, "r");
    if (fp == NULL) return;
    fgets(line, BUFFERSIZE, fp);
    fgets(line, BUFFERSIZE, fp); // skip the first two lines
    //__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "network init\n");
    while (fgets(line, BUFFERSIZE, fp) != NULL) {
        ++itfc_nbr;
        //__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "initlog %d\n", loggable);
    }
    fclose(fp);
    //__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Interface %d\n", itfc_nbr);

    net_working_list = (net_info*)malloc((RESERVED_SLOTS + itfc_nbr) * sizeof(net_info));
    memset(net_working_list, 0, (RESERVED_SLOTS + itfc_nbr) * sizeof(net_info));

    net_record_list = (net_info*)malloc((RESERVED_SLOTS + itfc_nbr) * sizeof(net_info));
    memset(net_record_list, 0, (RESERVED_SLOTS + itfc_nbr) * sizeof(net_info));

    received_speed = (int*)malloc((RESERVED_SLOTS + itfc_nbr) * sizeof (int));
    memset(received_speed, 0, (RESERVED_SLOTS + itfc_nbr) * sizeof (int));

    transimitted_speed = (int*)malloc((RESERVED_SLOTS + itfc_nbr) * sizeof (int));
    memset(transimitted_speed, 0, (RESERVED_SLOTS + itfc_nbr) * sizeof (int));

    net_dump();
    refresh_net();
    net_dump();
    refresh_net();
}

void net_dump()
{
    int i, rx, tx, interface_nbr = 0;
    char name[MAX_NAME_LEN], line[BUFFERSIZE];
    net_info *pt;
    FILE *fp = fopen(NETWORK, "r");
    if (fp == NULL) return;
    fgets(line, BUFFERSIZE, fp);
    fgets(line, BUFFERSIZE, fp); // skip the first two lines
    while (fgets(line, BUFFERSIZE, fp) != NULL) {
        sscanf(line, "%s %d %*d %*d %*d %*d %*d %*d %*d "
                "%d %*d %*d %*d %*d %*d %*d %*d", name, &rx, &tx);
        pt = net_working_list + interface_nbr;
        strcpy(pt->name, name);
        pt->rx = rx; // unit B
        pt->tx = tx;
        ++interface_nbr;
    }
    fclose(fp);
    itfc_nbr = interface_nbr;
}

void refresh_net()
{
    int i;
    total_net_received = 0;
    total_net_transmitted = 0;
    total_rx_speed = 0;
    total_tx_speed = 0;
    for (i=0; i<itfc_nbr; ++i) {
        long long currx = net_working_list[i].rx;
        long long curtx = net_working_list[i].tx;
        long long prerx = net_record_list[i].rx;
        long long pretx = net_record_list[i].tx;
        long long difrx = currx - prerx;
        long long diftx = curtx - pretx;
        received_speed[i] = difrx; /// interval;
        transimitted_speed[i] = diftx; // / interval; // TODO ??
        total_rx_speed += difrx;
        total_tx_speed += diftx;
        total_net_received += currx / 1024;
        total_net_transmitted += curtx / 1024;
        if (is_net_recording && loggable) {
            fprintf(net_logger, "%llu,%s,%llu,%llu\n", system_time, net_working_list[i].name,
                                                net_working_list[i].rx, net_working_list[i].tx);
            fflush(net_logger);
        }
    }
    swap_ptr((void*)&net_working_list, (void*)&net_record_list);
}


void net_cleanup()
{
    if (net_logger) fclose(net_logger);
    if (net_working_list) free(net_working_list);
    if (net_record_list) free(net_record_list);
    if (received_speed) free(received_speed);
    if (transimitted_speed) free(transimitted_speed);
}

void get_net_name_by_index(int index, char *buf)
{
    buf[0] = 0;
    if (net_index_inside(index)) {
        snprintf(buf, BUFFERSIZE, "%s", net_record_list[index].name);
    }
    return;
}

int net_index_inside(int index)
{
    return 0 <= index && index < itfc_nbr;
}

long long get_net_rx_by_index(int index)
{
    if (net_index_inside(index)) {
        return net_record_list[index].rx;
    } else return 0;
}

long long get_net_tx_by_index(int index)
{
    if (net_index_inside(index)) {
        return net_record_list[index].tx;
    } else return 0;
}

int get_net_rxspeed_by_index(int index)
{
    if (net_index_inside(index)) {
        return received_speed[index];
    } else return 0;
}

int get_net_txspeed_by_index(int index)
{
    if (net_index_inside(index)) {
        return transimitted_speed[index];
    } else return 0;
}

long long get_net_total_rx()
{
    return total_net_received;
}

long long get_net_total_tx()
{
    return total_net_transmitted;
}

float get_net_total_rx_speed()
{
    return total_rx_speed;
}

float get_net_total_tx_speed()
{
    return total_tx_speed;
}

int get_net_nbr()
{
    return itfc_nbr;
}

static int r_is_net_recording = 0;

void set_net_logging()
{
    if (loggable && is_net_recording && !r_is_net_recording) {
        char timesuffix[BUFFERSIZE];
        r_is_net_recording = 1;
        make_filename(timesuffix);
        snprintf(net_filename, BUFFERSIZE, "%s/network_%s.log", LOGGER_PATH, timesuffix);
        net_logger = fopen(net_filename, "w");
        if (net_logger == NULL) {
            loggable = 0;
            // TODO notify UI that unable to create a file
            __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "net logging failed\n");
            return;
        }
        fprintf(net_logger, "seconds,interface,rx,dx\n");
        __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "net logging started\n");
    } else if (r_is_net_recording && !is_net_recording) {
        r_is_net_recording = 0;
        if (loggable) {
            if (net_logger == NULL) return;
            fclose(net_logger);
            __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "net logging stopped\n");
            struct stat st;
            stat(net_filename, &st);
            if (st.st_size == 0) {
                remove(net_filename); // remove file if it's zero size
                __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "empty net logging removed\n");
            }
        }
    }
}


